package com.xqb.modules.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xqb.common.constant.Constants;
import com.xqb.common.constants.TableConstants;
import com.xqb.common.core.domain.entity.SysUser;
import com.xqb.common.exception.ServiceException;
import com.xqb.common.utils.DateUtils;
import com.xqb.common.utils.SecurityUtils;
import com.xqb.common.utils.bean.BeanUtils;
import com.xqb.modules.domain.po.*;
import com.xqb.modules.domain.vo.*;
import com.xqb.modules.mapper.*;
import com.xqb.modules.service.ILesCourseService;
import com.xqb.system.mapper.SysUserMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 课程Service业务层处理
 *
 * @author xqb
 * @date 2024-10-14
 */
@Service
@Slf4j
public class LesCourseServiceImpl implements ILesCourseService {
    @Autowired
    private LesCourseMapper lesCourseMapper;
    @Autowired
    private LesCourseContentMapper lesCourseContentMapper;
    @Autowired
    private StdLikedRecordMapper stdLikedRecordMapper;
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private InsInstitutionMapper insInstitutionMapper;
    @Autowired
    private StdLearningLessonMapper stdLearningLessonMapper;
    @Autowired
    private LesCategoryMapper lesCategoryMapper;
    @Autowired
    private LesCourseTeacherMapper lesCourseTeacherMapper;
    @Autowired
    private LesCourseEvaluationMapper lesCourseEvaluationMapper;
    @Autowired
    private LesCourseInfoMapper lesCourseInfoMapper;
    @Autowired
    private LesCourseCatalogueServiceImpl lesCourseCatalogueService;
    @Autowired
    private StdLearningRecordServiceImpl stdLearningRecordService;


    /**
     * 查询课程
     *
     * @param id 课程主键
     * @return 课程
     */
    @Override
    public LesCourse selectLesCourseById(Long id) {
        return lesCourseMapper.selectLesCourseById(id);
    }

    /**
     * 查询课程列表
     * 
     * @param lesCourse 课程
     * @return 课程
     */
    @Override
    public List<LesCourse> selectLesCourseList(LesCourse lesCourse)
    {
        return lesCourseMapper.selectLesCourseList(lesCourse);
    }

    private static LesCourseInfo getLesCourseInfo(LesCourse lesCourse, LesCourseContent lesCourseContent) {
        // 使用构建器模式或工厂方法简化对象创建和属性设置
        LesCourseInfo lesCourseInfo = new LesCourseInfo();
        if (TableConstants.COURSE_TYPE_OFFLINE == lesCourse.getCourseType()) {
            // 设置课程信息的经纬度以及地址
            BeanUtils.copyProperties(lesCourse, lesCourseInfo);
        }
        lesCourseInfo.setId(null);//交给数据库生成
        lesCourseInfo.setCourseId(lesCourse.getId());
        lesCourseInfo.setCourseContentId(lesCourseContent.getId());
        return lesCourseInfo;
    }

    /**
     * 新增课程
     *
     * @param lesCourse 课程
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class) // 添加事务注解，以确保整个方法执行过程中的数据库操作要么全部成功，要么全部回滚
    public Long insertLesCourse(LesCourse lesCourse)
    {
        // 设置课程创建时间为当前时间
        lesCourse.setCreateTime(DateUtils.getNowDate());
        // 创建课程内容的实例
        LesCourseContent lesCourseContent = new LesCourseContent();
        // 将课程信息插入数据库，并返回插入的行数
        int counts = lesCourseMapper.insert(lesCourse);
        // 将课程信息复制到课程内容对象中
        BeanUtils.copyProperties(lesCourse, lesCourseContent);
        // 将课程内容信息插入数据库
        lesCourseContentMapper.insert(lesCourseContent);
        // 创建课程信息的实例
        LesCourseInfo lesCourseInfo = getLesCourseInfo(lesCourse, lesCourseContent);
        // 将课程信息插入数据库
        lesCourseInfoMapper.insert(lesCourseInfo);
        // 返回课程id
        return lesCourse.getId();
    }

    /**
     * 修改课程
     *
     * @param lesCourse 课程
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class) // 添加事务注解
    public Long updateLesCourse(LesCourse lesCourse) {
        lesCourse.setUpdateTime(DateUtils.getNowDate());
        // 更新课程内容
        LesCourseContent lesCourseContent = new LesCourseContent();
        BeanUtils.copyProperties(lesCourse, lesCourseContent);
        lesCourseMapper.updateLesCourse(lesCourse);
        lesCourseContentMapper.updateLesCourseContent(lesCourseContent);
        //返回课程id
        return lesCourse.getId();
    }


    /**
     * 批量删除课程
     * 
     * @param ids 需要删除的课程主键
     * @return 结果
     */
    @Override
    public int deleteLesCourseByIds(Long[] ids)
    {
        return lesCourseMapper.deleteLesCourseByIds(ids);

    }

    /**
     * 删除课程信息
     *
     * @param id 课程主键
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteLesCourseById(Long id) {
        int row = 0;
        row += lesCourseMapper.deleteLesCourseById(id);
        row += lesCourseContentMapper.deleteLesCourseContentById(id);
        row += lesCourseTeacherMapper.deleteLesCourseTeacherById(id);
        return row;
    }

    /**
     * 统计课程
     *
     * @param insId 机构id
     * @return 结果
     */
    @Override
    public InstitutionCourseStatisticsVo getInsCourseStatistics(Long insId) {
        // 创建一个LambdaQueryWrapper对象，用于构建查询条件
        LambdaQueryWrapper<LesCourse> lesCourseLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 设置查询条件：机构ID等于传入的insId
        lesCourseLambdaQueryWrapper.eq(LesCourse::getInsId, insId);

        // 查询总课程数
        Long courseCount = lesCourseMapper.selectCount(lesCourseLambdaQueryWrapper);

        // 设置查询条件：课程状态为上架
        lesCourseLambdaQueryWrapper.eq(LesCourse::getStatus, Constants.COURSE_ON_SHELF);
        // 查询未下架的课程数
        Long unShelvesCourseCount = lesCourseMapper.selectCount(lesCourseLambdaQueryWrapper);

        // 设置查询条件：课程状态为上架
        lesCourseLambdaQueryWrapper.eq(LesCourse::getStatus, Constants.COURSE_SHELF);
        // 查询已上架的课程数
        Long shelvesCourseCount = lesCourseMapper.selectCount(lesCourseLambdaQueryWrapper);

        // 设置查询条件：课程状态为下架
        lesCourseLambdaQueryWrapper.eq(LesCourse::getStatus, Constants.COURSE_DOWN_SHELF);
        // 查询已下架的课程数
        Long ofShelvesCourseCount = lesCourseMapper.selectCount(lesCourseLambdaQueryWrapper);

        // 设置查询条件：课程状态为完结
        lesCourseLambdaQueryWrapper.eq(LesCourse::getStatus, Constants.COURSE_FINISH);
        // 查询已完结的课程数
        Long finishCourseCount = lesCourseMapper.selectCount(lesCourseLambdaQueryWrapper);

        // 构造并返回结果对象
        return InstitutionCourseStatisticsVo.builder()
                .courseCount(courseCount)
                .unShelvesCourseCount(unShelvesCourseCount)
                .shelvesCourseCount(shelvesCourseCount)
                .ofShelvesCourseCount(ofShelvesCourseCount)
                .finishCourseCount(finishCourseCount)
                .build();

    }


    /**
     * 获取课程详细信息
     *
     * @param id
     * @return
     */
    @Override
    public CourseAllInfoVo selectLesCourseInfoById(Long id) {
        log.info("获取课程详细信息:{}", id);
        CourseAllInfoVo courseAllInfoVo = new CourseAllInfoVo();

        // 查询课程基本信息和内容信息
        LesCourse lesCourse = lesCourseMapper.selectLesCourseById(id);
        LesCourseContent lesCourseContent = lesCourseContentMapper.selectLesCourseContentById(id);
        if (lesCourse != null && lesCourseContent != null) {
            BeanUtils.copyProperties(lesCourse, courseAllInfoVo);
            BeanUtils.copyProperties(lesCourseContent, courseAllInfoVo);
        }

        // 设置课程的点赞状态
        setCourseLikeStatus(courseAllInfoVo, id);

        // 设置课程的状态类型
        setCourseStatusType(courseAllInfoVo, id);

        // 查询课程的学习人数和评价人数
        setCourseEnrollAndEvaluationNum(courseAllInfoVo, id);

        return courseAllInfoVo;
    }

    /**
     * 设置课程点赞状态
     *
     * @param courseAllInfoVo 课程详细信息对象
     * @param id              课程ID
     */
    private void setCourseLikeStatus(CourseAllInfoVo courseAllInfoVo, Long id) {
        Long userId = getAuthenticatedUserId();
        if (userId != null) {
            StdLikedRecord stdLikedRecord = stdLikedRecordMapper.selectOne(new LambdaQueryWrapper<StdLikedRecord>()
                    .eq(StdLikedRecord::getBizId, id)
                    .eq(StdLikedRecord::getBizType, Constants.COURSE_LIKE)
                    .eq(StdLikedRecord::getUserId, userId));
            courseAllInfoVo.setLike(stdLikedRecord != null);
        } else {
            courseAllInfoVo.setLike(false);
        }
    }

    /**
     * 设置课程的状态类型
     *
     * @param courseAllInfoVo 课程详细信息对象
     * @param id              课程ID
     */
    private void setCourseStatusType(CourseAllInfoVo courseAllInfoVo, Long id) {
        Long userId = getAuthenticatedUserId();
        if (userId != null) {
            LambdaQueryWrapper<StdLearningLesson> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(StdLearningLesson::getCourseId, id).eq(StdLearningLesson::getUserId, userId);
            StdLearningLesson stdLearningLesson = stdLearningLessonMapper.selectOne(queryWrapper);
            if (stdLearningLesson != null) {
                courseAllInfoVo.setStatusType(Constants.COURSE_NO_BUY);
                if (stdLearningLesson.getExpireTime().after(new Date())) {
                    courseAllInfoVo.setStatusType(Constants.COURSE_EXPIRE);
                } else {
                    courseAllInfoVo.setStatusType(Constants.COURSE_BUY);
                }
            }
        }
    }

    /**
     * 获取当前已认证用户的ID
     *
     * @return 已认证用户的ID，如果未认证则返回null
     */
    private Long getAuthenticatedUserId() {
        try {
            return SecurityUtils.getUserId();
        } catch (ServiceException e) {
            return null;
        }
    }

    /**
     * 设置课程学习人数和评论数
     *
     * @param courseAllInfoVo 课程信息对象
     * @param id              课程ID
     */
    private void setCourseEnrollAndEvaluationNum(CourseAllInfoVo courseAllInfoVo, Long id) {
        LambdaQueryWrapper<StdLearningLesson> stdLearningLessonLambdaQueryWrapper = new LambdaQueryWrapper<>();
        stdLearningLessonLambdaQueryWrapper.eq(StdLearningLesson::getCourseId, id);
        courseAllInfoVo.setEnrollNum(stdLearningLessonMapper.selectCount(stdLearningLessonLambdaQueryWrapper));
        LambdaQueryWrapper<LesCourseEvaluation> lesCourseEvaluationLambdaQueryWrapper = new LambdaQueryWrapper<>();
        lesCourseEvaluationLambdaQueryWrapper.eq(LesCourseEvaluation::getCourseId, id);
        courseAllInfoVo.setEvaluationNum(lesCourseEvaluationMapper.selectCount(lesCourseEvaluationLambdaQueryWrapper));
    }



    /**
     * 课程收藏或取消收藏
     *
     * @param id 课程id
     * @return
     */
    @Override
    public Boolean updateCourseLike(Long id) {
        // 创建查询条件
        LambdaQueryWrapper<StdLikedRecord> stdLikedRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 设置查询条件：业务ID等于传入的课程ID
        stdLikedRecordLambdaQueryWrapper.eq(StdLikedRecord::getBizId, id);
        // 设置查询条件：用户ID等于当前用户ID
        stdLikedRecordLambdaQueryWrapper.eq(StdLikedRecord::getUserId, SecurityUtils.getUserId());
        // 设置查询条件：业务类型等于课程收藏
        stdLikedRecordLambdaQueryWrapper.eq(StdLikedRecord::getBizType, Constants.COURSE_LIKE);

        // 查询是否已存在该课程的收藏记录
        StdLikedRecord stdLikedRecord = stdLikedRecordMapper.selectOne(stdLikedRecordLambdaQueryWrapper);

        // 如果已存在该课程的收藏记录
        if (stdLikedRecord != null) {
            // 删除该收藏记录
            stdLikedRecordMapper.deleteById(stdLikedRecord.getId());
            // 返回false，表示已取消收藏
            return false;
        }

        // 创建新的收藏记录对象
        StdLikedRecord newStdLikedRecord = new StdLikedRecord();
        // 设置业务ID
        newStdLikedRecord.setBizId(id);
        // 设置业务类型
        newStdLikedRecord.setBizType(Constants.COURSE_LIKE);
        // 设置用户ID
        newStdLikedRecord.setUserId(SecurityUtils.getUserId());
        // 插入新的收藏记录
        // 如果插入成功（返回值为插入的行数，大于0表示插入成功），则返回true，表示收藏成功
        return stdLikedRecordMapper.insert(newStdLikedRecord) > 0;
    }


    /**
     * 获取课程列表
     *
     * @param lesCourse 课程
     * @return 课程
     */
    @Override
    public List<CourseVo> getLesCourseList(LesCourse lesCourse) {
        // 查询课程列表
        List<LesCourse> lesCourses = lesCourseMapper.selectLesCourseList(lesCourse);
        // 初始化课程视图对象列表
        List<CourseVo> courseVos = new ArrayList<>(lesCourses.size());
        Set<Long> categoryIds = new HashSet<>();
        // 用于存储机构ID的集合
        Set<Long> insIds = new HashSet<>();

        // 遍历课程列表，提取用户ID和机构ID
        for (LesCourse course : lesCourses) {
            // 将分类ID添加到分类ID集合中
            categoryIds.add(course.getFirstCateId());
            categoryIds.add(course.getSecondCateId());
            categoryIds.add(course.getThirdCateId());
            // 将机构ID添加到机构ID集合中
            insIds.add(course.getInsId());
        }

        // 查询用户信息，并存储到Map中
//        Map<String, String> userMap = queryUsers(users);
        // 查询机构信息，并存储到Map中
        Map<Long, String> insMap = queryIns(insIds);
        // 查询分类信息，并存储到Map中
        Map<Long, String> cateMap = queryCategorys(categoryIds);
        // 遍历课程列表，创建课程视图对象
        for (LesCourse newLesCourse : lesCourses) {
            // 创建课程视图对象
            CourseVo courseVo = new CourseVo();
            // 将课程信息复制到课程视图对象中
            BeanUtils.copyProperties(newLesCourse, courseVo);
            // 设置分类名称
            courseVo.setFirstCateName(cateMap.getOrDefault(newLesCourse.getFirstCateId(), null));
            courseVo.setSecondCateName(cateMap.getOrDefault(newLesCourse.getSecondCateId(), null));
            courseVo.setThirdCateName(cateMap.getOrDefault(newLesCourse.getThirdCateId(), null));
            // 设置机构名称
            courseVo.setInsName(insMap.getOrDefault(newLesCourse.getInsId(), null));
            // 将课程视图对象添加到列表中
            courseVos.add(courseVo);
        }

        // 返回课程视图对象列表
        return courseVos;
    }

    private Map<Long, String> queryCategorys(Set<Long> categoryIds) {
        if (categoryIds.isEmpty()) {
            return Collections.emptyMap();
        }
        LambdaQueryWrapper<LesCategory> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(LesCategory::getId, categoryIds);
        queryWrapper.select(LesCategory::getId, LesCategory::getName);
        List<LesCategory> categories = lesCategoryMapper.selectList(queryWrapper);
        return categories.stream().collect(Collectors.toMap(LesCategory::getId, LesCategory::getName));
    }


    private Map<Long, String> queryUsers(Set<Long> userIds) {
        if (userIds.isEmpty()) {
            return Collections.emptyMap();
        }
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SysUser::getUserId, userIds);
        queryWrapper.select(SysUser::getUserId, SysUser::getNickName);
        List<SysUser> users = sysUserMapper.selectList(queryWrapper);
        return users.stream().collect(Collectors.toMap(SysUser::getUserId, SysUser::getNickName));
    }

    private Map<Long, String> queryIns(Set<Long> insIds) {
        if (insIds.isEmpty()) {
            return Collections.emptyMap();
        }
        LambdaQueryWrapper<InsInstitution> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(InsInstitution::getId, insIds);
        queryWrapper.select(InsInstitution::getId, InsInstitution::getFullName);
        List<InsInstitution> insList = insInstitutionMapper.selectList(queryWrapper);
        return insList.stream().collect(Collectors.toMap(InsInstitution::getId, InsInstitution::getFullName));
    }

    //todo: mysql导入es,需要将课程信息、机构信息、用户信息都导入es
    @Override
    public int importAll() {
        List<LesCourse> courses = lesCourseMapper.selectList(new QueryWrapper<>());
        return 0;
    }

    /**
     * 根据课程ID查询课程基本信息、目录和学习进度
     *
     * @param courseId 课程ID
     * @return CourseAndSectionVO对象，包含课程基本信息、目录和学习进度
     */
    @Override
    public CourseAndSectionVO queryCourseAndCatalogById(Long courseId) {
        // 获取当前用户ID
        Long userId = SecurityUtils.getUserId();

        // 根据课程ID查询课程信息
        LesCourse lesCourse = lesCourseMapper.selectById(courseId);
        if (lesCourse == null) {
            // 如果没有找到课程信息，则返回null
            return null;
        }

        // 创建CourseAndSectionVO对象
        CourseAndSectionVO courseAndSectionVO = new CourseAndSectionVO();
        // 设置课程ID
        courseAndSectionVO.setId(courseId);
        // 设置课程名称
        courseAndSectionVO.setName(lesCourse.getName());
        // 设置课程章节数
        courseAndSectionVO.setSections(lesCourse.getSectionNum());
        // 设置课程封面URL
        courseAndSectionVO.setCoverUrl(lesCourse.getCoverUrl());

        // 查询课程教师信息
        List<CourseTeacherVo> teachers = lesCourseTeacherMapper.getCourseTeachers(courseId);
        if (CollectionUtils.isNotEmpty(teachers)) {
            // 如果有教师信息，则设置教师昵称
            courseAndSectionVO.setTeacherName(teachers.get(0).getNickName());
        }

        // 查询课程目录信息
        courseAndSectionVO.setChapters(lesCourseCatalogueService.selectAllCatalogueList(courseId));

        // 查询当前用户的学习课程信息
        StdLearningLesson stdLearningLesson = stdLearningLessonMapper.selectOne(new LambdaQueryWrapper<StdLearningLesson>().eq(StdLearningLesson::getCourseId, courseId).eq(StdLearningLesson::getUserId, userId));
        if (stdLearningLesson == null) {
            // 如果没有学习信息，则返回courseAndSectionVO
            return courseAndSectionVO;
        }

        // 设置学习记录ID
        courseAndSectionVO.setLessonId(stdLearningLesson.getId());

        // 查询当前用户的学习记录
        List<StdLearningRecord> stdLearningRecords = stdLearningRecordService.selectStdLearningRecordOrderByTimeDesc(userId, stdLearningLesson.getId());
        if (CollectionUtils.isEmpty(stdLearningRecords)) {
            // 如果没有学习记录，则返回courseAndSectionVO
            return courseAndSectionVO;
        }

        // 将学习记录按章节ID映射
        Map<Long, StdLearningRecord> rMap = stdLearningRecords.stream()
                .collect(Collectors.toMap(StdLearningRecord::getSectionId, r -> r));

        // 设置最新学习章节ID
        courseAndSectionVO.setLatestSectionId(stdLearningRecords.get(0).getLessonId());

        // 遍历课程目录，设置每个章节的学习进度和时刻
        for (LesAllCatalogueVo chapter : courseAndSectionVO.getChapters()) {
            for (SectionVO child : chapter.getChildren()) {
                StdLearningRecord r = rMap.get(child.getId());
                if (r != null) {
                    child.setFinished(r.getFinished().equals(1));
                    child.setMoment(Math.toIntExact(r.getMoment()));
                }
            }
        }

        // 返回CourseAndSectionVO对象
        return courseAndSectionVO;
    }

    /**
     * 判断用户是否已经购买了某课程。
     *
     * @param courseId 课程ID
     * @param userId   用户ID
     * @return 如果用户已购买该课程且课程未过期，则返回true；否则返回false
     */
    @Override
    public Boolean isBuyCourse(Long courseId, Long userId) {
        // 如果用户ID为空，则认为用户未购买任何课程
        if (userId == null) {
            return false;
        }

        // 创建查询条件
        LambdaQueryWrapper<StdLearningLesson> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(StdLearningLesson::getCourseId, courseId); // 根据课程ID查询
        queryWrapper.eq(StdLearningLesson::getUserId, userId);       // 根据用户ID查询

        // 执行查询，获取用户的学习记录
        StdLearningLesson stdLearningLesson = stdLearningLessonMapper.selectOne(queryWrapper);

        // 如果没有找到学习记录，则认为用户未购买该课程
        if (stdLearningLesson == null) {
            return false;
        }

        // 如果找到了学习记录，但课程已过期，则认为用户未购买该课程
        return !stdLearningLesson.getExpireTime().before(new Date());
    }
}
